package da.metricscraft.listeners;

import java.awt.geom.Point2D;
import java.util.HashMap;

import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerAnimationEvent;
import org.bukkit.event.player.PlayerAnimationType;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerInventoryEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.util.Vector;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import da.metricscraft.MetricsCraft;
import da.metricscraft.information.MovementInformation.MoveActions;
import da.metricscraft.information.PlayerInformation;
import da.metricscraft.information.PlayerInformation.PlayerDataType;
import da.metricscraft.threads.InformationGatherer;
import da.metricscraft.threads.InformationGatherer.Xmls;
import da.metricscraft.threads.MovementHandler;
import da.metricscraft.threads.MovementHandler.MovementStruct;

public class MetricsPlayerListener implements Listener{
	private static MetricsCraft plugin;
	private HashMap<Player, Vector> playersPrevPos;
	private HashMap<Player, Material> currentBlockInteracted;
	private HashMap<Player, Point2D.Double> playerLastExactPosition;
	private MovementHandler mh;
	public MetricsPlayerListener(MetricsCraft plugin){
		plugin.getServer().getPluginManager().registerEvents(this, plugin);
		playersPrevPos = new HashMap<Player, Vector>();
		playerLastExactPosition = new HashMap<Player, Point2D.Double>();
		currentBlockInteracted = new HashMap<Player, Material>();
		mh = new MovementHandler();
		MetricsPlayerListener.plugin = plugin;
	}
//	@EventHandler
//	public void onInventoryOpen(InventoryOpenEvent event){
//		MetricsCraft.log.info("[MetricsPlayerListener][onPlayerInventory] Event happened");
//		event.getInventory().toString();
//	}
	
	@EventHandler
	public void onPlayerJoin(PlayerJoinEvent event) {
		//plugin.getServer().getWorld("world").setTime(0);
		int life = 0;
		if (!plugin.enabled(event.getPlayer()))
			plugin.toggleMetricsCraft(event.getPlayer());
		if (InformationGatherer.getInstance() != null){
			Document movementXML = InformationGatherer.getInstance().getXML(Xmls.MOVEMENT);
			NodeList n =  movementXML.getElementsByTagName("player");
			for (int i = 0; i < n.getLength(); i++){
				if (n.item(i).getAttributes().getNamedItem("name").getTextContent().equalsIgnoreCase(event.getPlayer().getDisplayName())){
					life = Integer.parseInt(n.item(i).getLastChild().getAttributes().getNamedItem("lifetime").getTextContent());
					break;
				}
			}
			Document playerXML = InformationGatherer.getInstance().getXML(Xmls.PLAYER);
			NodeList player =  playerXML.getElementsByTagName("player");
			Node myElement = null;
			for (int i = 0; i < player.getLength(); i++){
				if (player.item(i).getAttributes().getNamedItem("name").getTextContent().equalsIgnoreCase(event.getPlayer().getDisplayName())){
					myElement = player.item(i);
					break;
				}
			}
			PlayerInformation pi = new PlayerInformation(event.getPlayer().getDisplayName());
			if(myElement != null){
				pi.load(myElement);
			}else{
				MetricsCraft.log.info("[MetricsPlayerListener][onPlayerJoin]: Player not registered.");
				pi.setData(PlayerDataType.LIFETIME, life);
			}
			
			plugin.mcPlayerData.put(event.getPlayer(), pi);
			
		}
		if (!plugin.mcPlayerLifetime.containsKey(event.getPlayer()))
			plugin.mcPlayerLifetime.put(event.getPlayer(), life);
	}
	
	@EventHandler
	public void onPlayerQuit(PlayerQuitEvent event) {
		int currentLiveTime = plugin.mcPlayerLifetime.remove(event.getPlayer());
		plugin.mcPlayerLifetime.put(event.getPlayer(), event.getPlayer().getTicksLived() + currentLiveTime);
		plugin.setPlayerData(event.getPlayer(), PlayerDataType.LIFETIME, event.getPlayer().getTicksLived() + currentLiveTime);
		InformationGatherer.getInstance().putInformation(plugin.mcPlayerData.get(event.getPlayer()));
	}
	@EventHandler
	public void onPlayerInteract(PlayerInteractEvent event) {
		if (plugin.enabled(event.getPlayer())){
			if (event.hasBlock()){
				String displayPlayer = event.getPlayer().getDisplayName();
				Material blocktype = event.getClickedBlock().getType();
				if (event.getAction() == Action.RIGHT_CLICK_BLOCK){
					if (blocktype == Material.CHEST && event.getAction() == Action.RIGHT_CLICK_BLOCK){
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.CHESTS_OPENED, 1);
					}else if (blocktype == Material.LEVER || blocktype == Material.STONE_BUTTON){
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.BUTTONS_PRESSED, 1);
					}
				}
				MetricsCraft.log.info("Player " + displayPlayer + 
						" used " + event.getMaterial().name() + " on " + event.getClickedBlock().getType().name());
				
				currentBlockInteracted.put(event.getPlayer(), event.getClickedBlock().getType());
				
			}
		}
	}
	@EventHandler
	public void onPlayerInventory(PlayerInventoryEvent event){
		
	}
	
	@EventHandler
	public void onPlayerAnimation(PlayerAnimationEvent event){
		if (event.getAnimationType() == PlayerAnimationType.ARM_SWING){
			if (currentBlockInteracted.get(event.getPlayer()) != Material.AIR && currentBlockInteracted.get(event.getPlayer()) != null){
				plugin.addPlayerData(event.getPlayer(), PlayerDataType.MININGTIME, 1);
				
			}
		}
	}
	@EventHandler
	public void onPlayerMove(PlayerMoveEvent event) {
		if (plugin.enabled(event.getPlayer())){
			Vector prevPos = playersPrevPos.get(event.getPlayer());
			Point2D.Double currentExactPos = playerLastExactPosition.get(event.getPlayer());
			//--- Create last position ---
			if (prevPos == null){
				double x = event.getPlayer().getLocation().toVector().getX();
				double y = event.getPlayer().getLocation().toVector().getY();
				double z = event.getPlayer().getLocation().toVector().getZ();
				prevPos = new Vector((int)x, (int)y, (int)z);
				currentExactPos = new Point2D.Double(x, z);
				mh.addMovement(new MovementStruct(event.getPlayer(), event.getPlayer().getTicksLived() + plugin.mcPlayerLifetime.get(event.getPlayer()), prevPos, MoveActions.MOVE));
				if (mh.getState() == Thread.State.NEW){
					mh.start();
				}
				
				playerLastExactPosition.put(event.getPlayer(), currentExactPos);
				playersPrevPos.put(event.getPlayer(), prevPos);
			}
			//----------------------------

			World world = plugin.getServer().getWorld("world");
			Vector curPos = new Vector((int)event.getPlayer().getLocation().toVector().getX(),
				(int)event.getPlayer().getLocation().toVector().getY(),
				(int)event.getPlayer().getLocation().toVector().getZ());
			
			if (!prevPos.toString().equals(curPos.toString())){
				mh.addMovement(new MovementStruct(event.getPlayer(), event.getPlayer().getTicksLived() + plugin.mcPlayerLifetime.get(event.getPlayer()), prevPos, MoveActions.MOVE));
				if (mh.getState() == Thread.State.NEW){
					mh.start();
				}
				playersPrevPos.put(event.getPlayer(), curPos);
				Material currentBlockMat = world.getBlockAt(event.getPlayer().getLocation()).getType();
				if ((int)prevPos.getY() < (int)curPos.getY() && currentBlockMat != Material.STATIONARY_WATER && currentBlockMat != Material.WATER){
					plugin.addPlayerData(event.getPlayer(), PlayerDataType.JUMPS, 1);
				}
			}
			
			Point2D.Double exactCurPos = new Point2D.Double(event.getPlayer().getLocation().toVector().getX(), event.getPlayer().getLocation().toVector().getZ());
			
			if (!currentExactPos.toString().equals(exactCurPos.toString())){
				playerLastExactPosition.put(event.getPlayer(), exactCurPos);
				Material highestBlock = world.getHighestBlockAt((int)curPos.getX(), (int)curPos.getZ()).getType();
				int high = world.getHighestBlockYAt((int)curPos.getX(), (int)curPos.getZ());
				while (highestBlock == Material.AIR || highestBlock == Material.LEAVES || highestBlock == Material.VINE){
					highestBlock = world.getBlockAt((int)curPos.getX(), --high, (int)curPos.getZ()).getType();
				}
				if (high > (int)curPos.getY()){
					plugin.addPlayerData(event.getPlayer(), PlayerDataType.UNDERGROUNDTIME, 1);
				}
				Material blocktype = world.getBlockAt(event.getPlayer().getLocation()).getType();
				if (blocktype == Material.WATER || blocktype == Material.STATIONARY_WATER){
					if (event.getPlayer().isInsideVehicle()){
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.BOATTIME, 1);
					}else
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.SWIMTIME, 1);
						
				}else{
					if (event.getPlayer().isSneaking()){
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.CROUCHTIME, 1);
					}else if (event.getPlayer().isSprinting()){
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.SPRINTTIME, 1);
					}else
						plugin.addPlayerData(event.getPlayer(), PlayerDataType.RUNTIME, 1);
				}
			}
			
		}
	}
}
